﻿using System;
using System.Collections.Generic;
using System.Text;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;
using System.Diagnostics;
using System.Collections.Specialized;

namespace CanSWAT.ArcSWAT
{
    class ProjectDatabase : PersonalDatabase
    {
        public ProjectDatabase(string file,Project prj) : base(file)
        {
            _parentProject = prj;
        }

        public override bool IsValid
        {
            get 
            {
                try
                {
                    return FinalHRUTable != null && MasterProgressTable != null;
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.ToString());
                    return false;
                }
            }
        }
        
        private static string FULL_HRU_NAME = "FullHRU";
        private static string TABLE_NAME_FINAL_HRU = "hrus";
        private static string TABLE_NAME_SPLIT_HRU = "SplitHrus";
        private static string TABLE_NAME_MASTER_PROGRESS = "MasterProgress";
        private static string TABLE_NAME_SUBBASIN = "sub";

        public static string FIELD_NAME_SLOPE_ALONG_WIND = "SLP_W";   //add three columns to table hrus
        public static string FIELD_NAME_CURVATURE_ALONG_WIND = "CUR_W";
        private static string FIELD_NAME_MEAN_SLOPE_CURVATURE = "MEAN";
        private static string FIELD_NAME_SUBBASIN = "SUBBASIN"; //subbasin field in table sub
        private static string FIELD_NAME_P_LAPSE_RATE = "PLAPS"; //precipitation lapse rate field in table sub
        private static string FIELD_NAME_T_LAPSE_RATE = "TLAPS"; //temperature lapse rate field in table sub

        public static string FIELD_NAME_HRUS_UNIAQUECOMB = "UNIQUECOMB";
        public static string FIELD_NAME_HRUS_LANDUSE = "LANDUSE";
        private static string FIELD_NAME_WIND_DIRECTION = "WINDDIR";
        private static string FIELD_NAME_HRU_GIS = "HRU_GIS";        
        
        private IFeatureClass _fullHRU = null;
        private SortedDictionary<int,HRU> _originalHRUs = null;

        private ITable _finalHRUTable = null;
        private StringCollection _finalHRUCodes = null;
        private SortedDictionary<int, Subbasin> _subbasins = null;

        private Dictionary<string, Landuse> _splitLanduses = null;

        private ITable _masterProgressTable = null;
        private int _windDirection = -99;

        private ITable _subbasinTable = null;

        private Project _parentProject = null;

        private ITable MasterProgressTable
        {
            get
            {
                if (_masterProgressTable == null) _masterProgressTable = openTable(TABLE_NAME_MASTER_PROGRESS);
                return _masterProgressTable;
            }
        }        

        public int WindDirection
        {
            get
            {
                if (_windDirection == -99)
                {
                    if (MasterProgressTable == null) return -1;

                    ICursor cursor = MasterProgressTable.Search(null, false);
                    IRow r = cursor.NextRow();
                    if (r == null) return -1;

                    int index = r.Fields.FindField(FIELD_NAME_WIND_DIRECTION);
                    if (index == -1)
                    {
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);

                        //add this column if necessary
                        addDoubleField(MasterProgressTable, FIELD_NAME_WIND_DIRECTION,-1.0);
                        return -1;
                    }

                    string sdir = r.get_Value(index).ToString();
                    int dir = -1;
                    if (sdir.Length > 0) dir = Convert.ToInt32(sdir);

                    System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
                    return dir;
                }
                return _windDirection;
            }
            set
            {
                if (_windDirection == value) return;

                if (MasterProgressTable == null) return;

                ICursor cursor = MasterProgressTable.Update(null, false);
                IRow r = cursor.NextRow();
                if (r == null) return;

                int index = r.Fields.FindField(FIELD_NAME_WIND_DIRECTION);
                if (index == -1)
                {
                    Debug.WriteLine("Warning: Couldn't find field " + FIELD_NAME_WIND_DIRECTION + " in table MasterProcess");
                    return;
                }

                r.set_Value(index,Convert.ToDouble(value));
                cursor.UpdateRow(r);

                System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);

                Debug.WriteLine("Information: Wind direction is saved in table MasterProcess.");
            }
        }

        private Dictionary<string, Landuse> SplitLanduses
        {
            get
            {
                if (_splitLanduses == null)
                {
                    _splitLanduses = new Dictionary<string, Landuse>();

                    IWorkspace2 wp2 = Workspace as IWorkspace2;
                    if (!wp2.get_NameExists(esriDatasetType.esriDTTable, TABLE_NAME_SPLIT_HRU)) return _splitLanduses;

                    //open the table
                    ITable splitTable = Workspace.OpenTable(TABLE_NAME_SPLIT_HRU);

                    //generate the filter to order results by landuse
                    IQueryFilter qf = new QueryFilterClass();
                    IQueryFilterDefinition qfd = qf as IQueryFilterDefinition;
                    qfd.PostfixClause = "ORDER BY LANDUSE";

                    //get the results
                    ICursor cursor = splitTable.Search(qf, false);
                    IRow r = cursor.NextRow();

                    while (r != null)
                    {
                        string landuse = r.get_Value(1).ToString();
                        
                        if (!_splitLanduses.ContainsKey(landuse))
                            _splitLanduses.Add(landuse, new Landuse(landuse));
                        
                        string sublanduse = r.get_Value(2).ToString();
                        double percentage = Convert.ToDouble(r.get_Value(3).ToString());
                        Landuse lu = _splitLanduses[landuse];
                        lu.AddSubLanduse(sublanduse, percentage);                         

                        r = cursor.NextRow();
                    }
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
                }
                return _splitLanduses;
            }
        }

        private IFeatureClass FullHRU
        {
            get
            {
                if (_fullHRU == null)
                {
                    IWorkspace2 wp2 = Workspace as IWorkspace2;
                    if (!wp2.get_NameExists(esriDatasetType.esriDTFeatureClass, FULL_HRU_NAME))
                    {
                        throw new System.Exception("Can't find " + FULL_HRU_NAME + " in porject database. " + 
                            "Please re-run the 'HRU Analysis --> Land Use/Soils/Slope Definition' and check the 'Create HRU Feature Class' option.");
                    }
                    _fullHRU = Workspace.OpenFeatureClass(FULL_HRU_NAME);
                }
                return _fullHRU;                      
            }
        }


        /// <summary>
        /// HRUs corresponding to FullHRU shapefile. These are not the final HRUs
        /// modeled in the model. Final HRUs are at table hrus.
        /// </summary>
        private SortedDictionary<int, HRU> OrignialHRUs
        {
            get
            {     

                if (_originalHRUs == null)
                {
                    IFeatureCursor cursor = FullHRU.Search(null, false);
                    IFeature fea = cursor.NextFeature();

                    if (fea != null) _originalHRUs = new SortedDictionary<int, HRU>();
                    while (fea != null)
                    {
                        int sub = Convert.ToInt32(fea.get_Value(HRU.SUBBAIN_INDEX).ToString());

                        _originalHRUs.Add(fea.OID, new HRU(fea,Subbasins[sub],SplitLanduses,FinalHRUCodes));
                        fea = cursor.NextFeature();
                    }
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
                }
                return _originalHRUs;
            }
        }

        private ITable FinalHRUTable
        {
            get
            {
                if (_finalHRUTable == null) _finalHRUTable = openTable(TABLE_NAME_FINAL_HRU);
                return _finalHRUTable;
            }
        }

        private SortedDictionary<int, Subbasin> Subbasins
        {
            get 
            {
                if (_subbasins == null)
                {
                    ICursor cursor = FinalHRUTable.Search(null, false);
                    IRow r = cursor.NextRow();

                    if (r != null) _subbasins = new SortedDictionary<int, Subbasin>();
                    while (r != null)
                    {
                        int subid = Convert.ToInt32(r.get_Value(Subbasin.SUBBAIN_ID_INDEX).ToString());
                        if (!_subbasins.ContainsKey(subid))
                            _subbasins.Add(subid,new Subbasin(r));

                        r = cursor.NextRow();
                    }
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
                }
                return _subbasins;
            }
        }

        /// <summary>
        /// The codes of final HRUs modeled in the the model. It's used to filter 
        /// HRUs from orignial HRU table (FullHRU)
        /// </summary>
        private StringCollection FinalHRUCodes
        {
            get
            {
                if (_finalHRUCodes == null) _finalHRUCodes = getUniqueCodeList(FinalHRUTable,FIELD_NAME_HRUS_UNIAQUECOMB);
                return _finalHRUCodes;
            }
        }

        /// <summary>
        /// Get a list of all unique value from given table for given field. Similar with 
        /// the distinct function in SQL. The distinct function is only supported starting
        /// from ArcGIS 10.0 (interface IQueryFilterDefinition2).
        /// </summary>
        /// <param name="t">The table</param>
        /// <param name="fieldName">Name of the field</param>
        /// <returns></returns>
        private StringCollection getUniqueCodeList(ITable t, string fieldName)
        {
            ICursor cursor = t.Search(null, false);
            try
            {
                IRow r = cursor.NextRow();

                if (r != null)
                {
                    int index = r.Fields.FindField(fieldName);
                    if (index == -1)
                        throw new System.Exception(
                            "Can't find field " + fieldName + " in table " + (t as IDataset).Name);

                    StringCollection list = new StringCollection();
                    while (r != null)
                    {
                        string code = r.get_Value(index).ToString();
                        if (!list.Contains(code)) list.Add(code);                        

                        r = cursor.NextRow();
                    }
                    return list;
                }
                return new StringCollection();
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
            }
        }

        /// <summary>
        /// calculate mean slope/curvature for each polygon in FullHRU and save it into FullHRU.
        /// New columns will be added if they don't exist.
        /// </summary>
        /// <param name="db"></param>
        /// <param name="type"></param>
        /// <param name="isSave"></param>
        public void calSlope(RasterDatabase db,SlopeType type,bool isSave)
        {
            //do the spaital analysis
            ITable t = db.calSlope(FullHRU,type);

            //read mean slope/curvature to HRU ojects
            int meanIndex = t.Fields.FindField(FIELD_NAME_MEAN_SLOPE_CURVATURE);
            ICursor cursor = t.Search(null, false);
            IRow r = cursor.NextRow();
            while (r != null)
            {
                if (OrignialHRUs.ContainsKey(r.OID))
                {
                    double slope = Convert.ToDouble(r.get_Value(meanIndex).ToString());
                    if (type == SlopeType.Slope)
                        OrignialHRUs[r.OID].SlopeAlongWind = slope;
                    else
                        OrignialHRUs[r.OID].CurvatureAlongWind = slope;
                }                    
                else
                    Debug.WriteLine("Warning: Can't find HRU " + r.OID.ToString());
                
                r = cursor.NextRow();
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);

            if (!isSave) return;

            string slopeColName = FIELD_NAME_SLOPE_ALONG_WIND;
            if(type == SlopeType.Curvature)
                slopeColName = FIELD_NAME_CURVATURE_ALONG_WIND;

            //try to add the new column
            addDoubleField(FullHRU as ITable, slopeColName,0.0);
 
            //update FullHRU
            int slopeIndex = FullHRU.Fields.FindField(slopeColName);
            IFeatureCursor updateCursor = FullHRU.Update(null, false);
            IFeature fea = updateCursor.NextFeature();
            while (fea != null)
            {
                if (type == SlopeType.Slope)
                    fea.set_Value(slopeIndex, OrignialHRUs[fea.OID].SlopeAlongWind);
                else
                    fea.set_Value(slopeIndex, OrignialHRUs[fea.OID].CurvatureAlongWind);

                updateCursor.UpdateFeature(fea);

                fea = updateCursor.NextFeature();
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(updateCursor);
        }

        /// <summary>
        /// Add a double field in given table with given name. If the table or feature class
        /// is being used, an error will happen.
        /// </summary>
        /// <param name="t">Destination table, also could be feature class</param>
        /// <param name="fieldName">The name of the field</param>
        private void addDoubleField(ITable t, string fieldName, double defaultValue)
        {
            if (t.Fields.FindField(fieldName) < 0)
            {
                ISchemaLock schemaLock = (ISchemaLock)t;
                try
                {
                    // A try block is necessary, as an exclusive lock may not be available.
                    schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);

                    IField nf = new FieldClass();
                    IFieldEdit f = nf as IFieldEdit;
                    f.Name_2 = fieldName;
                    f.Type_2 = esriFieldType.esriFieldTypeDouble;
                    f.DefaultValue_2 = defaultValue;
                    f.AliasName_2 = fieldName;

                    t.AddField(nf);

                    Debug.WriteLine("Information: Field " + fieldName + " is added to table/feature class " + (t as IDataset).Name);
                }
                catch (System.Exception)
                {
                    throw new System.Exception(
                        "The feature class/table " + (t as IDataset).Name + " is opened in another application. Please close them bofore you could proceed.");
                }
                finally
                {
                    // Set the lock to shared, whether or not an error occurred.
                    schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
                }
            }
        }

        public void calHRUParameter(bool isSave)
        {
            Debug.WriteLine("Calculating slope and curvatrue of all HRUs...");

            foreach (HRU hru in OrignialHRUs.Values)
                hru.reCalParameters();              //get parameters

            if (!isSave) return;

            //try to add the new columns
            addDoubleField(FinalHRUTable, FIELD_NAME_SLOPE_ALONG_WIND,0.0);
            addDoubleField(FinalHRUTable, FIELD_NAME_CURVATURE_ALONG_WIND,0.0);

            Debug.WriteLine("Saving slope and curvatrue of all HRUs to table hrus...");
            foreach (HRU hru in OrignialHRUs.Values)
                hru.saveParameters(FinalHRUTable);  //save to parameters
        }

        /// <summary>
        /// write hru_sr.txt based on values in table hrus
        /// </summary>
        /// <param name="srPath">The file path which will be saved</param>
        public void writeSnowRedistributionParameterFile(string srPath)
        {
            IQueryFilter qf = new QueryFilterClass();
            IQueryFilterDefinition qfd = qf as IQueryFilterDefinition;
            qfd.PostfixClause = "ORDER BY " + FIELD_NAME_HRU_GIS;

            ICursor cursor = FinalHRUTable.Search(qf, false);
            try
            {
                IRow r = cursor.NextRow();

                int index_hru_gis = r.Fields.FindField(FIELD_NAME_HRU_GIS);
                int index_slope = r.Fields.FindField(FIELD_NAME_SLOPE_ALONG_WIND);
                int index_curvature = r.Fields.FindField(FIELD_NAME_CURVATURE_ALONG_WIND);
                int index_landuse = r.Fields.FindField(FIELD_NAME_HRUS_LANDUSE);

                if (index_slope == -1 || index_curvature == -1)
                    throw new System.Exception("Please set wind direction first!");

                System.Text.StringBuilder sb = new StringBuilder();
                string format = "{0}\t{1}\t{2:F3}\t{3:F3}\t{4}\t{5}";
                sb.AppendLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", "subbasin", "hru", "slope", "curvature","shc_con","shc_no"));

                int shc_converntional_till = 10;
                int shc_no_till = 10;                    
                while (r != null)
                {
                    string hru_gis = r.get_Value(index_hru_gis).ToString();
                    string landuse = r.get_Value(index_landuse).ToString();
                    int sub = Convert.ToInt32(hru_gis.Substring(0, 5).ToString());
                    int hru = Convert.ToInt32(hru_gis.Substring(5).ToString());

                    double slope = Convert.ToDouble(r.get_Value(index_slope).ToString());
                    double curvature = Convert.ToDouble(r.get_Value(index_curvature).ToString());

                    if(SnowHoldingCapacities.ContainsKey(landuse))
                    {
                        LanduseSnowHoldingCapacity shc = SnowHoldingCapacities[landuse];
                        shc_converntional_till = shc.ConventionalTill;
                        shc_no_till = shc.NoTill;
                    }
                    else
                    {
                        shc_converntional_till = 40;
                        shc_no_till = 40;   
                    }

                    sb.AppendLine(string.Format(format, sub, hru, slope, curvature,
                        shc_converntional_till,shc_no_till));

                    r = cursor.NextRow();
                }

                //write hru_sr.txt
                using (System.IO.StreamWriter writer = new System.IO.StreamWriter(srPath))
                {
                    writer.Write(sb.ToString());
                }
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
            }

        }

        #region Snow Holding Capacity

        private static string TABLE_NAME_SNOW_HOLDING_CAPACITY = "shc";
        private ITable _shcTable = null;

        private SortedDictionary<string, LanduseSnowHoldingCapacity> _snowHoldingCapacities = null;

        private StringCollection _finalHRULanduses = null;

        private ITable SnowHoldingCapacityTable
        {
            get
            {
                if (_shcTable == null)
                {
                    addDefaultSnowHodlingCapacity();
                    _shcTable = openTable(TABLE_NAME_SNOW_HOLDING_CAPACITY);
                }
                    
                return _shcTable;
            }
        }

        /// <summary>
        /// The codes of final HRUs modeled in the the model. It's used to filter 
        /// HRUs from orignial HRU table (FullHRU)
        /// </summary>
        private StringCollection FinalHRULanduses
        {
            get
            {
                if (_finalHRULanduses == null) 
                    _finalHRULanduses = getUniqueCodeList(FinalHRUTable, FIELD_NAME_HRUS_LANDUSE);
                return _finalHRULanduses;
            }
        }

        /// <summary>
        /// create default snow holding capacity table based on crop and urban table in swat2009.mdb.
        /// </summary>
        private void addDefaultSnowHodlingCapacity()
        {
            IWorkspace2 wp2 = Workspace as IWorkspace2;
            if (wp2.get_NameExists(esriDatasetType.esriDTTable, TABLE_NAME_SNOW_HOLDING_CAPACITY)) return;
                
            //create the table
            try
            {
                Workspace.CreateTable(TABLE_NAME_SNOW_HOLDING_CAPACITY, 
                    LanduseSnowHoldingCapacity.DefaultFields, null, null, "");
            }
            catch (System.Exception e)
            {
                CanSWAT.showInformationWindow(e.ToString());
            }

            //add default values
            _snowHoldingCapacities = _parentProject.ArcSWATDatabase.DefaultSnowHoldingCapacities;

            //check if landuse is used in final hru
            foreach (LanduseSnowHoldingCapacity shc in _snowHoldingCapacities.Values)
                shc.IsUsedInFinalHRU = FinalHRULanduses.Contains(shc.Code);

            IRowBuffer rowBuffer = SnowHoldingCapacityTable.CreateRowBuffer();
            ICursor insertCursor = SnowHoldingCapacityTable.Insert(true);

            try
            {
                foreach (LanduseSnowHoldingCapacity shc in _snowHoldingCapacities.Values)
                {
                    shc.save2row(rowBuffer);
                    insertCursor.InsertRow(rowBuffer);
                }
                insertCursor.Flush();
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(insertCursor);
            }
        }

        public void EditSnowHoldingCapacity()
        {
            SortedDictionary<string, LanduseSnowHoldingCapacity> shc_used = new SortedDictionary<string, LanduseSnowHoldingCapacity>();
            foreach (LanduseSnowHoldingCapacity shc in SnowHoldingCapacities.Values)
                if (shc.IsUsedInFinalHRU)
                    shc_used.Add(shc.Code, shc.Clone());

            SnowHoldingCapacityFrm frm = new SnowHoldingCapacityFrm(shc_used);
            if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //save the edits
                try
                {
                    foreach (LanduseSnowHoldingCapacity shc in shc_used.Values)
                        shc.update(SnowHoldingCapacityTable);

                    _snowHoldingCapacities = null; //force to re-read the table next time.
                    CanSWAT.showInformationWindow("Snow holding capacity is updated!");
                }
                catch (System.Exception e)
                {
                    CanSWAT.showInformationWindow(e.ToString());
                }

            }
        }

        private SortedDictionary<string, LanduseSnowHoldingCapacity> SnowHoldingCapacities
        {
            get
            {
                addDefaultSnowHodlingCapacity();

                if (_snowHoldingCapacities == null)
                {
                    _snowHoldingCapacities = new SortedDictionary<string, LanduseSnowHoldingCapacity>();

                    //read shc from table shc
                    ICursor cursor = SnowHoldingCapacityTable.Search(null, false);
                    IRow r = cursor.NextRow();
                    while (r != null)
                    {
                        LanduseSnowHoldingCapacity shc = new LanduseSnowHoldingCapacity(r);
                        _snowHoldingCapacities.Add(shc.Code, shc);

                        r = cursor.NextRow();
                    }
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);

                    //if current snow holding capacity table is empty, try to get default one
                    if (_snowHoldingCapacities.Count == 0)
                        _snowHoldingCapacities = _parentProject.ArcSWATDatabase.DefaultSnowHoldingCapacities;
                
                    //check if landuse is used in final hru
                    foreach (LanduseSnowHoldingCapacity shc in _snowHoldingCapacities.Values)
                        shc.IsUsedInFinalHRU = FinalHRULanduses.Contains(shc.Code);
                }

                return _snowHoldingCapacities;
            }
        }

        #endregion

        #region Elevation Band

        /// <summary>
        /// flag to indentify if subbasin elevations has been read
        /// </summary>
        private bool _hasGotSubbasinElevation = false;

        /// <summary>
        /// generate elevation band with given information. The information will be save in table sub
        /// </summary>
        /// <param name="raster">RasterDatabase object in the same project</param>
        /// <param name="p">Elevation band generation parameter</param>
        /// <param name="method">Elevation band generation method, equal elevation or equal area</param>
        /// <param name="numOfBand">Number of bands</param>
        /// <param name="initialSnow">initial snow</param>
        /// <param name="precipitationLapseRate">precipitation lapse rate</param>
        /// <param name="temperatureLapseRate">temperature lapse rate</param>
        private void generateElevationBand(IElevationBandGenerationParameter p)
        {
            CanSWAT.debugInformation(string.Format("Parameter of elevation band generation: method = {0}, number of band = {1}, " +  
                "initial snow = {2} mm, precipitation laps rate = {3} mm/km, temperature laps rate = {4} degree/km",
                p.Method,p.NumberOfBands,p.InitialSnow,p.PrecipitationLapsRate,p.TemperatureLapsRate));
            

            //get subbasin elevation if necessary
            //only need to do once
            if (!_hasGotSubbasinElevation)
            {
                this.setProgress(10, "Reading Elevation...");
                this._parentProject.RasterDatabase.getSubbasinElevation(Subbasins);
                _hasGotSubbasinElevation = true;
            }

            //re-create elevation bands using given condition
            this.setProgress(50, "Creating Elevation Bands...");
            foreach (Subbasin sub in Subbasins.Values)
                sub.createElevationBands(p.Method, p.NumberOfBands, p.InitialSnow);

            //update table sub
            this.setProgress(80, "Saving Elevation Bands...");
            if (_subbasinTable == null) _subbasinTable = openTable(TABLE_NAME_SUBBASIN);
            int subIndex = _subbasinTable.Fields.FindField(FIELD_NAME_SUBBASIN);
            int tLapsIndex = _subbasinTable.Fields.FindField(FIELD_NAME_T_LAPSE_RATE);
            int pLapsIndex = _subbasinTable.Fields.FindField(FIELD_NAME_P_LAPSE_RATE);

            ICursor updateCursor = _subbasinTable.Update(null, false);
            try
            {
                IRow r = updateCursor.NextRow();
                while (r != null)
                {
                    int subid = Convert.ToInt32(r.get_Value(subIndex).ToString());

                    if (!Subbasins.ContainsKey(subid))
                        Debug.WriteLine("Warning: Can't find subbasin " + subid.ToString());
                    else
                    {
                        Subbasins[subid].saveElevationBands2row(r);
                        r.set_Value(pLapsIndex, Convert.ToSingle(p.PrecipitationLapsRate));
                        r.set_Value(tLapsIndex, Convert.ToSingle(p.TemperatureLapsRate));

                        updateCursor.UpdateRow(r);
                    }

                    r = updateCursor.NextRow();
                }
                this.setProgress(100, "DONE!");
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(updateCursor);
            }
        }

        public void generateElevationBand()
        {
            ElevationBandFrm bandFrm = new ElevationBandFrm();
            if (bandFrm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                generateElevationBand(bandFrm as ArcSWAT.IElevationBandGenerationParameter);
                CanSWAT.showInformationWindow("Elevation Bands are generated!");
            }
        }

        public void displayElevationBand()
        {
            ElevationBandDisplayFrm bandFrm = new ElevationBandDisplayFrm(Subbasins);
            bandFrm.ShowDialog();
        }

        #endregion
    }
}
